package com.ruoyi.project.business.monthsalary;

import com.alibaba.fastjson.JSON;
import com.ruoyi.common.exception.CustomException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.project.business.askleave.request.ListAskLeaveRequest;
import com.ruoyi.project.business.askleave.response.AskLeaveResponse;
import com.ruoyi.project.business.askleave.service.IAskLeaveService;
import com.ruoyi.project.business.common.constant.BusinessConstant;
import com.ruoyi.project.business.monthsalary.entity.MonthSalary;
import com.ruoyi.project.business.monthsalary.request.CulMonthSalaryRequest;
import com.ruoyi.project.business.salarydetail.request.AddSalaryDetailRequest;
import com.ruoyi.project.business.salarydetail.service.ISalaryDetailService;
import com.ruoyi.project.business.salaryoptions.entity.SalaryOptions;
import com.ruoyi.project.business.salaryoptions.service.ISalaryOptionsService;
import com.ruoyi.project.business.salaryrule.entity.MonthSalaryRule;
import com.ruoyi.project.business.salaryrule.service.IMonthSalaryRuleService;
import com.ruoyi.project.business.tenantsocialsecurity.entity.TenantsocialSecurity;
import com.ruoyi.project.business.tenantsocialsecurity.service.ITenantsocialSecurityService;
import com.ruoyi.project.business.utils.BusinessUtil;
import com.ruoyi.project.system.entity.SysUser;
import com.ruoyi.project.system.service.ISysUserService;
import lombok.Builder;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.math.BigDecimal;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Slf4j
@Builder
public class SalaryDomain {
    private Long tenantId;
    private Long operatorId;
    private CulMonthSalaryRequest request;
    private MonthSalaryRule rule;
    private List<AskLeaveResponse> askLeaveResponses;
    private ISalaryOptionsService optionsService;
    private ITenantsocialSecurityService tenantsocialSecurityService;

    @Getter
    private final MonthSalary resultMonthSalary = new MonthSalary();
    @Getter
    private final AddSalaryDetailRequest resultSalaryDetail = new AddSalaryDetailRequest();;

    public SalaryDomain salary() {
        // 薪资计算规则 config

        Long userId = request.getUserId();
        Date yearMonth = request.getYearMonth();
        Integer year = DateUtils.year(yearMonth);
        Integer month = DateUtils.month(yearMonth);


        String formula = rule.getFormula();
        List<Long> optionIds = extractOptions(formula);
        List<SalaryOptions> salaryOptions = optionsService.selectSalaryOptionsByIds(optionIds, tenantId);
        if(CollectionUtils.isEmpty(salaryOptions) || salaryOptions.size() != optionIds.size()) {
            log.error("计算项异常：存在未知的计算项 {}", formula);
            throw new CustomException("计算项异常：存在未知的计算项");
        }

        // 记录到 schedule_salary_detail
        // 总薪
        BigDecimal totalsalary = getTotalsalary(formula, salaryOptions);

        // 扣税 TODO
        BigDecimal tax = BigDecimal.ZERO;
        // 扣社保
        BigDecimal socialSecurity = culSocialSecurity(tenantId, year, userId);
        // 扣请假
        SalaryOptions baseOption = findBaseOptions(salaryOptions);
        BigDecimal leaveDeduct = culLeave(tenantId, yearMonth, baseOption.getAmount(), userId);
        // 应发
        BigDecimal resultsalary = totalsalary.subtract(tax).subtract(socialSecurity).subtract(leaveDeduct);


        resultMonthSalary.setMonth(month);
        resultMonthSalary.setYear(year);
        resultMonthSalary.setAmount(resultsalary); // 记应发工资
        resultMonthSalary.setDueDate(rule.getDueDate());
        resultMonthSalary.setPayDate(rule.getPayDate());
        resultMonthSalary.setUserId(userId);


//        salaryDetail.setSalaryId(entity.getId()); // 确认下是否能拿到
        resultSalaryDetail.setMonth(month);
        resultSalaryDetail.setUserId(userId);
        resultSalaryDetail.setYear(year);
        resultSalaryDetail.setTotalsalary(totalsalary);
        resultSalaryDetail.setTax(tax);
        resultSalaryDetail.setSocialSecurity(socialSecurity);
        resultSalaryDetail.setResultsalary(resultsalary);
        return this;
    }

    private List<Long> extractOptions(String formula) {
        Pattern pattern = Pattern.compile("\\{([^}]*)\\}");
        Matcher matcher = pattern.matcher(formula);

        List<Long> res = new ArrayList<>();
        while (matcher.find()) {
            System.out.println(matcher.group(1));
            String match = matcher.group(1);
            if(StringUtils.isBlank(match)) {
                log.error("错误的公式 {}", formula);
                throw new CustomException("错误的公式：" + formula);
            }
            res.add(Long.valueOf(match));
        }
        if(res.size() <= 0) {
            throw new CustomException("错误的公式：" + formula);
        }
        return res;
    }

    private BigDecimal culSocialSecurity(Long tenantId, Integer year, Long userId) {
        BigDecimal socialSecurity = BigDecimal.ZERO;
        TenantsocialSecurity tenantsocialSecurity = tenantsocialSecurityService.selectByUser(year, userId, tenantId);
        if(tenantsocialSecurity != null) {
            BigDecimal baseAmt = tenantsocialSecurity.getBaseAmt();
            if (baseAmt != null) {
                // 计算社保
                socialSecurity = baseAmt.multiply(new BigDecimal(tenantsocialSecurity.getPercent())).divide(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP);
            }
        }
        return socialSecurity;
    }


    private BigDecimal culLeave(Long tenantId, Date yearMonth, BigDecimal baseSalary, Long userId) {
        BigDecimal leaveDeduct = BigDecimal.ZERO;

        if(CollectionUtils.isNotEmpty(askLeaveResponses)) {
            int totalLeaveHours = askLeaveResponses.stream().mapToInt(single -> {
                int hours = DateUtils.getHours(single.getApplyTimeStart(), single.getApplyTimeEnd());
                return hours;
            }).sum();
            //

            BigDecimal daySalary = baseSalary.divide(BigDecimal.valueOf(30) , BigDecimal.ROUND_CEILING).setScale(2); // 基本工资 / 30 得到人员的日薪
            leaveDeduct = daySalary.multiply(BigDecimal.valueOf(totalLeaveHours / 8)).setScale(2);
        }
        return leaveDeduct;
    }

    private static BigDecimal getTotalsalary(String formula, List<SalaryOptions> salaryOptions) {
        for (SalaryOptions opt : salaryOptions) {
            formula = StringUtils.replace(formula, "{" + opt.getId() + "}", opt.getAmount().toString());
        }
        BigDecimal totalsalary = BusinessUtil.culBySpring(formula);
        return totalsalary;
    }


    private SalaryOptions findBaseOptions(List<SalaryOptions> salaryOptions) {
        Optional<SalaryOptions> first = salaryOptions.stream().filter(tmp -> BusinessConstant.SALARY_OPTION_TYPE.BASE_FLAG.equals(tmp.getType())).findFirst();
        if(! first.isPresent()) {
            throw new CustomException("薪资结构中未包含：基本工资");
        }
        return first.get();
    }
}
